<?php

/**
 * 对称加密算法类
 */
class SymmetricEncryption
{

    const CIPHER = MCRYPT_RIJNDAEL_128;

    const MODEL = MCRYPT_MODE_CBC;

    const HASH_ALGORITHM = 'sha1';
    // 对应android、iOS的{0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF}
    const HASH_SALT = 'AAECAwQFBgcICQoLDA0ODw==';

    const HASH_ITERATIONS = 10000;
    // 对应android、iOS的 KEY_LENGTH/8
    const HASH_KEY_LENGTH = 32;
    // 对应android、iOS的{0xA,1,0xB,5,4,0xF,7,9,0x17,3,1,6,8,0xC,0xD,91}
    const IV = 'CgELBQQPBwkXAwEGCAwNWw==';

    /**
     * 加密
     * 
     * @param $key string
     *            加密密钥
     * @param $data string
     *            待加密明文
     * @return string 密文
     */
    public static function encrypt($key, $data)
    {
        // 对应安卓和iOS的PBKDF2WithHmacSHA1
        $key = hash_pbkdf2(self::HASH_ALGORITHM, $key, base64_decode(self::HASH_SALT), self::HASH_ITERATIONS, self::HASH_KEY_LENGTH, true);
        // 使用PKCS7Padding的方式进行填充
        $data = self::PKCS7Padding($data);
        // 创建和 AES 兼容的密文（Rijndael 分组大小 = 256）
        $cipherText = mcrypt_encrypt(self::CIPHER, $key, $data, self::MODEL, base64_decode(self::IV));
        // 对密文进行 base64 编码便于显性复制
        $cipherTextBase64 = base64_encode($cipherText);
        return $cipherTextBase64;
    }

    /**
     * 解密
     * 
     * @param $key string
     *            解密密钥
     * @param $data string
     *            待解密密文
     * @return string 明文
     */
    public static function decrypt($key, $data)
    {
        // 对应安卓和iOS的PBKDF2WithHmacSHA1
        $key = hash_pbkdf2(self::HASH_ALGORITHM, $key, base64_decode(self::HASH_SALT), self::HASH_ITERATIONS, self::HASH_KEY_LENGTH, true);
        // --- 解密 ---
        $cipherTextDec = base64_decode($data);
        $plaintextDec = mcrypt_decrypt(self::CIPHER, $key, $cipherTextDec, self::MODEL, base64_decode(self::IV));
        // 移除PKCS7Padding填充
        $plaintextDec = self::PKCS7REmovePadding($plaintextDec);
        return $plaintextDec;
    }

    /**
     * PKCS7Padding模式填充
     * 
     * @param
     *            $data
     * @return string
     */
    public static function PKCS7Padding($data)
    {
        $blockSize = mcrypt_get_block_size(self::CIPHER, self::MODEL);
        $pad = $blockSize - (strlen($data) % $blockSize);
        return $data . str_repeat(chr($pad), $pad);
    }

    /**
     * 移除PKCS7Padding模式填充
     * 
     * @param
     *            $data
     * @return string
     */
    public static function PKCS7RemovePadding($data)
    {
        $pad = ord($data[strlen($data) - 1]);
        return substr($data, 0, - $pad);
    }

    /**
     * 生成16位16进制对称加密密钥
     */
    public static function generateKey()
    {
        $num = '';
        for ($i = 0; $i < 16; $i ++) {
            $num .= dechex(rand(0, 15));
        }
        return $num;
    }

    /**
     * PKCS5Padding模式填充
     * 
     * @param
     *            $text
     * @param
     *            $blockSize
     * @return string
     */
    public static function PKCS5Padding($text, $blockSize)
    {
        $pad = $blockSize - (strlen($text) % $blockSize);
        return $text . str_repeat(chr($pad), $pad);
    }

    /**
     * 移除PKCS5Padding模式填充
     * 
     * @param
     *            $text
     * @return string
     */
    public static function PKCS5RemovePadding($text)
    {
        $pad = ord($text{strlen($text) - 1});
        if ($pad > strlen($text)) {
            return false;
        }
        if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
            return false;
        }
        return substr($text, 0, - 1 * $pad);
    }
}